package com.nrgedge.filter;

import info.magnolia.cms.filters.OncePerRequestAbstractMgnlFilter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;

public abstract class AbstractMustacheSubstitutionFilter extends OncePerRequestAbstractMgnlFilter {
	private static final Logger log = LoggerFactory.getLogger(AbstractMustacheSubstitutionFilter.class);

	@Override
	public void doFilter(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws IOException, ServletException {
		final FilterResponseWrapper wrapper = new FilterResponseWrapper(response);
		chain.doFilter(request, wrapper);
		substituteBeansIntoResponseBody(request, wrapper);
	}

	private void substituteBeansIntoResponseBody(final HttpServletRequest request, final FilterResponseWrapper wrapper) {
		final Mustache mustache = new DefaultMustacheFactory().compile(new StringReader(wrapper.getBody()), "");
		final StringWriter writer = new StringWriter();
		mustache.execute(writer, getBeans(request));
		writeToResponse(wrapper, writer.toString());
	}

	private static void writeToResponse(final FilterResponseWrapper wrapper, final String responseBody) {
		final OutputStream outputStream = wrapper.getOutputStream();
		try {
			outputStream.write(responseBody.getBytes());
		} catch (IOException exception) {
			log.error("Error writing to response OutputStream", exception);
		}
	}

	public abstract Map<String, Object> getBeans(final HttpServletRequest request);

	private static class FilterResponseWrapper extends HttpServletResponseWrapper {
		private int contentLength;
		private String contentType;
		private StringWriter bodyWriter;

		public FilterResponseWrapper(final HttpServletResponse response) {
			super(response);
			this.bodyWriter = new StringWriter();
		}

		public String getBody() {
			return this.bodyWriter.toString();
		}

		public ServletOutputStream getOutputStream() {
			try {
				return getResponse().getOutputStream();
			} catch (IOException exception) {
				log.error("Error getting response OutputStream", exception);
			}
			return null;
		}

		public PrintWriter getWriter() {
			return new PrintWriter(this.bodyWriter);
		}

		public void setContentLength(final int length) {
			this.contentLength = length;
			super.setContentLength(length);
		}

		@SuppressWarnings("unused")
		public int getContentLength() {
			return this.contentLength;
		}

		public void setContentType(final String type) {
			this.contentType = type;
			super.setContentType(type);
		}

		public String getContentType() {
			return this.contentType;
		}
	}
}